<?php
namespace app\websocket\controller;
use think\facade\Db;
use think\worker\Server;
use Workerman\Worker;
use Workerman\Lib\Timer;
class Websocketman extends Server
{
    protected $socket = 'websocket://0.0.0.0:9001';
    protected $client_id;
    protected $clientIdConnections;
    protected $context = [
        'ssl' => [
            'local_cert' => '/data/www/test.uumo.top.pem', //证书文件的存放路径（请改成自己的路径）
            'local_pk' => '/data/www/test.uumo.top.key', //证书私钥的存放路径（请改成自己的路径）
            'verify_peer' => false,
        ],
    ];
    protected $option = [
        'transport' => 'ssl',   //设置transport开启ssl，启用wss://
    ];

    /**
     * 收到信息
     * @param $connection
     * @param $data
     */
    public function onMessage($connection, $data)
    {
        $data = json_decode($data,true);
        if (!empty($data["type"]) && $data["type"] == "say") {
            $result["type"] = "say";
            $result["from"] = $data["from"];
            $result["to"] = $data["to"];
            $result["content"] = $data["content"];
            $this->clientIdConnections[$data["to"]]->send(json_encode($result,true));
        }
//        dump('参数:'.$data.'时间:'.date('Y-m-d H:i:s',time()));
        $connection->send(json_encode($data,true));
    }
    /**
     * 当连接建立时触发的回调函数
     * @param $connection
     */
    public function onConnect($connection)
    {
        // 生成一个唯一用户的客户端id
        $this->client_id = time().rand(0,9).rand(0,9).rand(0,9).rand(0,9);
        // 将生成的client_id赋给当前连接
        $connection->client_id = $this->client_id;

        // 在当前worker对象中新添属性  保存当前登录的用户的client_id 和 连接对象
        // 以便进行推送
        $this->clientIdConnections[$connection->client_id] = $connection;
        // 将生成的client_id发送给客户端
        $json = [
            'type'  =>  'bind',
            'from'  =>  'worker',
            'uid'    =>  $connection->client_id,
            'content' => $this->client_id
        ];
        $connection->send(json_encode($json,true));
//        $connection->send("连接成功");
    }

    /**
     * 当连接断开时触发的回调函数
     * @param $connection
     */
    public function onClose($connection)
    {
        if(isset($connection->client_id))
        {
            // 连接断开时删除映射
            unset($this->clientIdConnections[$connection->client_id]);
        }
    }

    /**
     * 当客户端的连接上发生错误时触发
     * @param $connection
     * @param $code
     * @param $msg
     */
    public function onError($connection, $code, $msg)
    {
        echo "error $code $msg\n";
    }

    /**
     * 每个进程启动
     * @param $worker
     */
    public function onWorkerStart($worker)
    {
// 开启一个内部端口，方便内部系统推送数据，Text协议格式 文本+换行符
        $inner_text_worker = new Worker('text://0.0.0.0:9002');
//        $inner_text_worker->reusePort=true;
        $inner_text_worker->onMessage = function ($connection, $buffer) {
            // $data数组格式，里面有uid，表示向那个uid的页面推送数据
            $data = json_decode($buffer, true);
            $uid = $data['uid'];
            // 通过workerman，向uid的页面推送数据
            $ret = $this->sendMessageByUid($uid, $buffer);
            // 返回推送结果
            $connection->send($ret ? 'ok' : 'fail');
        };
        // ## 执行监听 ##
        $inner_text_worker->listen();
        Timer::add(1, function () use ($worker) {
            $time_now = time();
            foreach ($worker->connections as $connection) {
                // 有可能该connection还没收到过消息，则lastMessageTime设置为当前时间
                if (empty($connection->lastMessageTime)) {
                    $connection->lastMessageTime = $time_now;
                    continue;
                }
                // 上次通讯时间间隔大于心跳间隔，则认为客户端已经下线，关闭连接
                if ($time_now - $connection->lastMessageTime > 3600) {
                    $connection->close();
                }
            }
        });
    }
    // 针对uid推送数据
    public function sendMessageByUid($uid, $message)
    {
        if(isset($this->clientIdConnections[$uid]))
        {
            $connection = $this->clientIdConnections[$uid];
            $connection->send($message);
            return true;
        }
        return false;
    }
}
